{"componentChunkName":"component---src-templates-post-js","path":"/simply-learn-full-stack-5","result":{"data":{"site":{"siteMetadata":{"title":"neohed","description":"Blog posts on web development and related areas","author":{"name":"neohed"},"keywords":["Web Development","JavaScript"]}},"mdx":{"frontmatter":{"title":"Full-Stack React & Node.js, Part 5 - Get client & server talking","description":"Tutorial to learn full-stack with React node.js and Prisma DB","date":"June 27, 2022","author":null,"banner":null,"slug":"simply-learn-full-stack-5","keywords":null},"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"slug\": \"simply-learn-full-stack-5\",\n  \"date\": \"2022-06-27T08:36:32\",\n  \"title\": \"Full-Stack React & Node.js, Part 5 - Get client & server talking\",\n  \"description\": \"Tutorial to learn full-stack with React node.js and Prisma DB\",\n  \"published\": true\n};\n\nvar makeShortcode = function makeShortcode(name) {\n  return function MDXDefaultShortcode(props) {\n    console.warn(\"Component \" + name + \" was not imported, exported, or provided by MDXProvider as global scope\");\n    return mdx(\"div\", props);\n  };\n};\n\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"h1\", null, \"Simply Learn Full-Stack React & Node.js\"), mdx(\"p\", null, \"Finally, the fun part is here! All our components are in place and now we only need to change 1 component to get the server and client talking.\"), mdx(\"p\", null, \"In \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"react-client\"), \", edit \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"AddEditNote.js\"), \", and replace the contents with this:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-jsx\"\n  }), \"import React, {useState, useEffect} from 'react';\\nimport RenderData from \\\"./RenderData\\\";\\nimport Form from './Form';\\n\\nconst AddEditNote = () => {\\n  const [note, setNote] = useState({});\\n\\n  useEffect( () => {\\n    async function fetchData() {\\n      console.log('Calling fetch...')\\n      const response = await fetch('http://localhost:4011/note');\\n\\n      if (response.ok) {\\n        console.log('Response received from server and is ok!')\\n        const {note} = await response.json();\\n\\n        setNote(note)\\n      }\\n    }\\n\\n    fetchData()\\n  }, [])\\n\\n  return (\\n    <div>\\n      <RenderData\\n        data={note}\\n      />\\n      <Form\\n        entity={note}\\n      />\\n    </div>\\n  );\\n};\\n\\nexport default AddEditNote;\\n\")), mdx(\"p\", null, \"To test this you will need 2 shell/CLI programs.\"), mdx(\"p\", null, \"Use one to run the server, in \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"node-server\"), \" folder, execute:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-shell\"\n  }), \"npm run start\\n\")), mdx(\"p\", null, \"The second in \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"react-client\"), \" folder, execute:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-shell\"\n  }), \"npm run start\\n\")), mdx(\"p\", null, \"Now, when your React site runs, and you click on \\\"Edit Post\\\" you will see a form with data that has been loaded from the server.\"), mdx(\"p\", null, \"If you take a look at the shell/CLI where you ran your Node.js server you should see the requests logged by \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, mdx(\"em\", {\n    parentName: \"strong\"\n  }, \"morgan\")), \".\"), mdx(\"p\", null, \"There's a problem here though!\"), mdx(\"p\", null, mdx(\"span\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"482px\"\n    }\n  }), \"\\n      \", mdx(\"a\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/static/1bfc522af90366956f5837c18d1056d5/11908/log.jfif\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": [\"noopener\"]\n  }), \"\\n    \", mdx(\"span\", _extends({\n    parentName: \"a\"\n  }, {\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"27.7992277992278%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGUAD//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAVEAEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAQABPyGv/9oADAMBAAIAAwAAABCAD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABkQAAEFAAAAAAAAAAAAAAAAAHEAARARkf/aAAgBAQABPxAGVjI//9k=')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  })), \"\\n  \", mdx(\"img\", _extends({\n    parentName: \"a\"\n  }, {\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"node server request log\",\n    \"title\": \"node server request log\",\n    \"src\": \"/static/1bfc522af90366956f5837c18d1056d5/11908/log.jfif\",\n    \"srcSet\": [\"/static/1bfc522af90366956f5837c18d1056d5/f22ee/log.jfif 259w\", \"/static/1bfc522af90366956f5837c18d1056d5/11908/log.jfif 482w\"],\n    \"sizes\": \"(max-width: 482px) 100vw, 482px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\"\n  })), \"\\n  \"), \"\\n    \")), mdx(\"p\", null, \"Each time we visit the form we see two GET requests on the server.\"), mdx(\"p\", null, \"If you open the dev console in Chrome with F12 and go to the network tab you will also see duplicated requests here!\"), mdx(\"p\", null, mdx(\"span\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"733px\"\n    }\n  }), \"\\n      \", mdx(\"a\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/static/2473827079ca3599866010aca3d8aa00/7881b/chrome-network.jfif\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": [\"noopener\"]\n  }), \"\\n    \", mdx(\"span\", _extends({\n    parentName: \"a\"\n  }, {\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"29.72972972972973%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAckFBP/EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEAAQUCf//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABsQAAIBBQAAAAAAAAAAAAAAAAARASExUWGh/9oACAEBAAE/IXW49inPD//aAAwDAQACAAMAAAAQ89//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAEAAwEBAAAAAAAAAAAAAAABABEhMWH/2gAIAQEAAT8QsYUXTrPJgJ0XH//Z')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  })), \"\\n  \", mdx(\"img\", _extends({\n    parentName: \"a\"\n  }, {\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"Chrome network tab\",\n    \"title\": \"Chrome network tab\",\n    \"src\": \"/static/2473827079ca3599866010aca3d8aa00/7881b/chrome-network.jfif\",\n    \"srcSet\": [\"/static/2473827079ca3599866010aca3d8aa00/f22ee/chrome-network.jfif 259w\", \"/static/2473827079ca3599866010aca3d8aa00/6c8d3/chrome-network.jfif 518w\", \"/static/2473827079ca3599866010aca3d8aa00/7881b/chrome-network.jfif 733w\"],\n    \"sizes\": \"(max-width: 733px) 100vw, 733px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\"\n  })), \"\\n  \"), \"\\n    \")), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"Pro tip: if your Chrome network tab doesn't show what you expect, make sure the correct category is selected. Look at the second row in the image above and you will see \\\"Fetch/XHR\\\" selected.\")), mdx(\"p\", null, \"Let's check the Chrome console to see what we've logged out:\"), mdx(\"p\", null, mdx(\"span\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"381px\"\n    }\n  }), \"\\n      \", mdx(\"a\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/static/b127c523e1d08a2a33ad3756d3f8a9d3/20d9d/chrome-console.jfif\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": [\"noopener\"]\n  }), \"\\n    \", mdx(\"span\", _extends({\n    parentName: \"a\"\n  }, {\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"39.38223938223938%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAc2RAX//xAAXEAADAQAAAAAAAAAAAAAAAAAAAhIB/9oACAEBAAEFAq0pi2P/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAYEAADAQEAAAAAAAAAAAAAAAAAMaEBMv/aAAgBAQAGPwLqjo9P/8QAGRAAAQUAAAAAAAAAAAAAAAAAABEhMUHx/9oACAEBAAE/IWJBC40j/9oADAMBAAIAAwAAABCML//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABsQAQACAgMAAAAAAAAAAAAAAAEAESHRUWHx/9oACAEBAAE/EHnKZLbhcox77ntZ/9k=')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  })), \"\\n  \", mdx(\"img\", _extends({\n    parentName: \"a\"\n  }, {\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"Chrome console logs\",\n    \"title\": \"Chrome console logs\",\n    \"src\": \"/static/b127c523e1d08a2a33ad3756d3f8a9d3/20d9d/chrome-console.jfif\",\n    \"srcSet\": [\"/static/b127c523e1d08a2a33ad3756d3f8a9d3/f22ee/chrome-console.jfif 259w\", \"/static/b127c523e1d08a2a33ad3756d3f8a9d3/20d9d/chrome-console.jfif 381w\"],\n    \"sizes\": \"(max-width: 381px) 100vw, 381px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\"\n  })), \"\\n  \"), \"\\n    \")), mdx(\"p\", null, \"Sure enough, we call fetch twice, and receive a response twice. What is going on here?\"), mdx(\"p\", null, \"This kind of thing is quite common, and in apps with a very complex structure of many nested components, you might see the same requests repeated 10, 12 or more times.\"), mdx(\"p\", null, \"This is due to the way React will re-render components when either the props or the state changes.  Which, of course is exactly what React is supposed to do. As developers we need to be careful when we fetch data inside, what is essentially, UI rendering code.\"), mdx(\"p\", null, \"So, are we doomed? Do we just give up and go home?\"), mdx(\"p\", null, mdx(\"span\", _extends({\n    parentName: \"p\"\n  }, {\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"399px\"\n    }\n  }), \"\\n      \", mdx(\"a\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/static/a98a97b302206960de456e7c260b81f3/349e6/meme.jfif\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": [\"noopener\"]\n  }), \"\\n    \", mdx(\"span\", _extends({\n    parentName: \"a\"\n  }, {\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"100.77220077220078%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAEDBAL/xAAWAQEBAQAAAAAAAAAAAAAAAAACAAP/2gAMAwEAAhADEAAAAdmSnjUQoKuAWMO//8QAGxAAAgIDAQAAAAAAAAAAAAAAAQIAEgMQESH/2gAIAQEAAQUCjsLE+hyscitorchy81//xAAXEQADAQAAAAAAAAAAAAAAAAAAEBEx/9oACAEDAQE/AdI//8QAFhEBAQEAAAAAAAAAAAAAAAAAARAx/9oACAECAQE/AXYz/8QAHhAAAQQBBQAAAAAAAAAAAAAAAQACEBExIjJRcZH/2gAIAQEABj8CR0tjKuxfEYB7Wxnkf//EAB0QAAICAgMBAAAAAAAAAAAAAAERADEhgRBRYXH/2gAIAQEAAT8hQVCAiBEclQLYGoCvCzuNovsZNjpDIGfeP//aAAwDAQACAAMAAAAQtziA/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAQEf/aAAgBAwEBPxAQXMZ//8QAGBEAAgMAAAAAAAAAAAAAAAAAARARITH/2gAIAQIBAT8QoAhbX//EAB0QAQEAAQUBAQAAAAAAAAAAAAERACExQVFxEKH/2gAIAQEAAT8QJejkyIDORd44tAq2CB5giAdLfzCOaKhiHCOoMdC8BuTzBNQ3Wj8//9k=')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  })), \"\\n  \", mdx(\"img\", _extends({\n    parentName: \"a\"\n  }, {\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"Never Give Up toddler meme\",\n    \"title\": \"Never Give Up toddler meme\",\n    \"src\": \"/static/a98a97b302206960de456e7c260b81f3/349e6/meme.jfif\",\n    \"srcSet\": [\"/static/a98a97b302206960de456e7c260b81f3/f22ee/meme.jfif 259w\", \"/static/a98a97b302206960de456e7c260b81f3/349e6/meme.jfif 399w\"],\n    \"sizes\": \"(max-width: 399px) 100vw, 399px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\"\n  })), \"\\n  \"), \"\\n    \")), mdx(\"p\", null, \"To fix this we need to keep track of requests that have been made, and cancel them when the component unmounts, and ignore any responses that might sometimes return from cancelled requests.\"), mdx(\"p\", null, \"Edit \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"AddEditNote.js\"), \" again, to this code:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-jsx\"\n  }), \"import React, {useState, useEffect} from 'react';\\nimport RenderData from \\\"./RenderData\\\";\\nimport Form from './Form';\\n\\nconst AddEditNote = () => {\\n  const [note, setNote] = useState({});\\n\\n  useEffect( () => {\\n    const abortController = new AbortController();\\n\\n    async function fetchData() {\\n      console.log('Calling fetch...')\\n      try {\\n        const response = await fetch('http://localhost:4011/note', {\\n          signal: abortController.signal,\\n        });\\n\\n        if (response.ok) {\\n          console.log('Response received from server and is ok!')\\n          const {note} = await response.json();\\n\\n          if (abortController.signal.aborted) {\\n            console.log('Abort detected, exiting!')\\n            return;\\n          }\\n\\n          setNote(note)\\n        }\\n      } catch(e) {\\n        console.log(e)\\n      }\\n    }\\n\\n    fetchData()\\n\\n    return () => {\\n      console.log('Aborting GET request.')\\n      abortController.abort();\\n    }\\n  }, [])\\n\\n  return (\\n    <div>\\n      <RenderData\\n        data={note}\\n      />\\n      <Form\\n        entity={note}\\n      />\\n    </div>\\n  );\\n};\\n\\nexport default AddEditNote;\\n\")), mdx(\"p\", null, \"We use the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"AbortController\"), \" as a signal passed as an option to the fetch request. When the component unmounts we abort any requests. And, just in case a request slipped through before being aborted, we check the abort state when a request returns.\"), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"This bug is common in production code bases. With each user action triggering multiple fetch requests causing the server to make multiple DB requests, your servers might end up with 10 times the load they should have.\")), mdx(\"p\", null, \"If you save and run the code again, you will see that duplicate requests are cancelled and we only hit the server with a single GET request each time we visit the form. Good job - bug fixed!\"), mdx(\"p\", null, \"In the next part, we will explore other HTTP verbs to make data mutations on the server...\"), mdx(\"p\", null, mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"/simply-learn-full-stack-6\"\n  }), \"Next we're going to \", mdx(\"strong\", {\n    parentName: \"a\"\n  }, \"POST\"), \" data to our server from the client\"), \", ...\"), mdx(\"p\", null, \"Code repo: \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://github.com/neohed/node-react-stack\"\n  }), \"Github Repository\")));\n}\n;\nMDXContent.isMDXComponent = true;"}},"pageContext":{"id":"d50e9e7d-2aa1-5ec2-bf62-2070f5612432","prev":{"id":"2390e060-6276-55f3-89cf-91f581fdf491","parent":{"name":"index","sourceInstanceName":"blog"},"excerpt":"Simply Learn Full-Stack React & Node.js First create a folder  node-server  at the same level as folder  react-client Inside the  node-server  folder, use a shell/CLI to enter this command to create a  package.json  file: The  -y  flag means that…","fields":{"title":"Simply Learn Full-Stack Web, Part 3","description":"Tutorial to learn full-stack with React node.js and Prisma DB","slug":"simply-learn-full-stack-3","absolutePath":"D:/Workspace/Github/neohed-blog/content/blog/learn-full-stack-simply-03/index.mdx","banner":null,"date":"2022-06-27T08:36:32"}},"next":{"id":"6c4ad356-f047-5f7b-91dd-1f8fdf8296ed","parent":{"name":"index","sourceInstanceName":"blog"},"excerpt":"Remix Rap, Part Two Validation blog post part 2 There are many flavours of validation UX.  You can use some combination of onChange, onBlur, onFocus and potentially others. Things to consider:\nDo you want to display an error message, e.g., 'ERROR…","fields":{"title":"Remix Rap Part Two","description":"Remix React form validation","slug":"remix-rap-two","absolutePath":"D:/Workspace/Github/neohed-blog/content/blog/remix-rap-two/index.mdx","banner":null,"date":"2022-05-24T16:41:23"}}}}}